using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;

using Peradigm.Framework.Domain.Security;
using Peradigm.Framework.Persistence;

using Liberty.Domain.ApprovalManagement;
using Liberty.Domain.GrantManagement;
using Liberty.Domain.NoteManagement;
using Liberty.Domain.ServiceMemberManagement;

namespace Liberty.Domain.CaseManagement
{
    [Serializable]
    public class Case : PersistentModel, INotable, IEquatable<Case>
    {
        #region Constants
        #endregion

        #region Event Handlers
        #endregion

        #region Methods
  

        /// <summary>
        /// 
        /// </summary>
        /// <param name="newGrant">
        /// </param>
        /// <returns>
        /// </returns>
        public Grant AddGrant( Grant newGrant )
        {
            if( !this.primGrants.Contains( newGrant ) )
            {
                this.primGrants.Add( newGrant );
            }

            if( newGrant.Case != null && newGrant.Case != this )
            {
                newGrant.Case.RemoveGrant( newGrant );
            }
            newGrant.Case = this;

            return newGrant;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="newInjury">
        /// </param>
        /// <returns>
        /// </returns>
        public Injury AddInjury( Injury newInjury )
        {
            if( !this.primInjuries.Contains( newInjury ) )
            {
                this.primInjuries.Add( newInjury );
            }

            return newInjury;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="newNote">
        /// </param>
        /// <returns>
        /// </returns>
        public Note AddNote( Note newNote )
        {
            primNotes.Add( newNote );
            return newNote;
        }

        /// <summary>
        /// Add a collection of notes to my existing collection and answer the collection back to the caller.
        /// </summary>
        /// <param name="notes">An enumerable container of notes.</param>
        /// <returns>The collection that was passed as a parameter.</returns>
        public ICollection<Note> AddNotes( ICollection<Note> notes )
        {
            foreach( Note newNote in notes )
            {
                this.AddNote( newNote );
            }
            return notes;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="newVisit"><
        /// /param>
        /// <returns>
        /// </returns>
        public Visit AddVisit( Visit newVisit )
        {
            if( !primVisits.Contains( newVisit ) )
            {
                primVisits.Add( newVisit );
            }

            return newVisit;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns>
        /// </returns>
        public Visit CurrentVisit      
        {
            get
            {
                Visit currentVisit = null;
                if( this.primVisits.Count > 0 )
                {
                    currentVisit = this.primVisits[this.primVisits.Count - 1];
                }
                return currentVisit;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="aCase">
        /// </param>
        /// <returns>
        /// </returns>
        public bool Equals( Case aCase )
        {
            return this.Oid == aCase.Oid;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="grant">
        /// </param>
        /// <returns>
        /// </returns>
        public Grant RemoveGrant( Grant grant )
        {
            if( primGrants.Contains( grant ) )
            {
                primGrants.Remove( grant );
            }
            return grant;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="injury">
        /// </param>
        /// <returns>
        /// </returns>
        public Injury RemoveInjury( Injury injury )
        {
            if( primInjuries.Contains( injury ) )
            {
                primInjuries.Remove( injury );
            }
            return injury;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="note"></param>
        /// <returns></returns>
        public Note RemoveNote( Note note )
        {
            if( primNotes.Contains( note ) )
            {
                primNotes.Remove( note );
            }
            return note;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="visit"></param>
        /// <returns></returns>
        public Visit RemoveVisit( Visit visit )
        {
            if( primVisits.Contains( visit ) )
            {
                primVisits.Remove( visit );
            }
            return visit;
        }

        public void RemoveNotes()
        {
            this.primNotes.Clear();
        }
        #endregion

        #region Properties
        public DateTime? DateOfInjury
        {
            get
            {
                if( this.primDateOfInjury.HasValue )
                {
                    return primDateOfInjury.Value;
                }
                else
                {
                    return null;
                }
            }
            set
            {
                if( value.HasValue )
                {
                    primDateOfInjury = value;
                }
                else
                {
                    primDateOfInjury = null;
                }
            }
        }

        public IEnumerable<Event> Events
        {
            get
            {
                return primEvents;
            }
        }

        public IEnumerable<Grant> Grants
        {
            get
            {
                return primGrants;
            }
        }

        public IEnumerable<Injury> Injuries
        {
            get
            {
                return primInjuries;
            }
        }

        public IEnumerable<Note> Notes
        {
            get
            {
                return primNotes;
            }
        }

        public ServiceMember ServiceMember
        {
            get
            {
                return i_ServiceMember;
            }
            set
            {
                i_ServiceMember = value;
            }
        }

        public Decimal TotalAmount
        {
            get
            {
                decimal total = 0;
                if( this.Grants != null )
                {
                    foreach( Grant grant in this.Grants )
                    {
                        total += grant.Value;
                    }
                }
                return total;
            }
        }

        public IEnumerable<Visit> Visits
        {
            get
            {
                return primVisits;
            }
        }

        public CaseVolunteer Volunteer
        {
            get
            {
                return i_CaseVolunteer;
            }
            set
            {
                i_CaseVolunteer = value;
            }
        }
        #endregion

        #region Private Methods
        #endregion

        #region Private Properties
        private DateTime? primDateOfInjury
        {
            get
            {
                return i_DateOfInjury;
            }
            set
            {
                i_DateOfInjury = value;
            }
        }

        private List<Event> primEvents
        {
            get
            {
                return i_Events;
            }
        }

        private List<Grant> primGrants
        {
            get
            {
                return i_Grants;
            }
        }

        private List<Injury> primInjuries
        {
            get
            {
                return i_Injuries;
            }
        }

        private List<Note> primNotes
        {
            get
            {
                return i_Notes;
            }
        }

        private List<Visit> primVisits
        {
            get
            {
                return i_Visits;
            }
        }
        #endregion

        #region Construction and Finalization
        /// <summary>
        /// Creates a stubbed case populated with frequently used primitives.
        /// Other aggregated objects are not populated by this factory method.
        /// </summary>
        /// <returns></returns>
        public static Case TestInstance()
        {
            List<Injury> injuries = new List<Injury>();
            injuries.Add( Injury.TestInstance() );
            Case stub = new Case( 12L, PersistentModel.NEW_VERSION, injuries, ServiceMember.TestInstance(), CaseVolunteer.TestInstance() );
            stub.AddGrant( Grant.TestInstance() );

            return stub;
        }

        public Case()
        {
        }

        public Case( CaseVolunteer volunteer )
        {
            volunteer.AddCase( this );
            this.Volunteer = volunteer;
        }

        public Case( long oid, byte[] version, IEnumerable<Injury> injuries, ServiceMember serviceMember, CaseVolunteer caseVolunteer )
        {
            this.Oid = oid;
            this.Version = version;
            this.i_Injuries.Clear();
            this.i_Injuries.AddRange( injuries );
            //serviceMember.AddCase( this );
            this.ServiceMember = serviceMember;
            this.Volunteer = caseVolunteer;
        }

        public Case( long oid, byte[] version, IEnumerable<Injury> injuries, ServiceMember serviceMember, CaseVolunteer caseVolunteer, IEnumerable<Grant> grants )
            : this( oid, version, injuries, serviceMember, caseVolunteer )
        {
            this.i_Grants.Clear();
            this.i_Grants.AddRange( grants );
        }
        #endregion

        #region Data Elements
        private CaseVolunteer i_CaseVolunteer;
        private DateTime? i_DateOfInjury;
        private List<Event> i_Events = new List<Event>();
        private List<Grant> i_Grants = new List<Grant>();
        private List<Injury> i_Injuries = new List<Injury>();
        private List<Note> i_Notes = new List<Note>();
        private ServiceMember i_ServiceMember;
        private List<Visit> i_Visits = new List<Visit>();
        #endregion

    }
}


